package net.zoneland.knowledge.utils;

import java.io.IOException;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.message.BasicHeader;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.zoneland.knowledge.config.EsConfigInterface;

/**
 * ElasticSearch 连接池工具类.
 *
 * @author bcc
 */
public final class ElasticSearchPoolUtil {

    /**
     * logger.
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(ElasticSearchPoolUtil.class);

    /**
     * ES配置.
     */
    private static EsConfigInterface esConfig;

    private static RestClientBuilder restClientBuilder;

    private ElasticSearchPoolUtil() {

    }

    /**
     * 获得对象.
     *
     * @return
     * @throws Exception Exception
     */
    public static RestHighLevelClient getClient() throws Exception {
        restClientBuilder.setRequestConfigCallback(requestConfigBuilder -> {
            requestConfigBuilder.setConnectionRequestTimeout(500000);
            requestConfigBuilder.setSocketTimeout(3600000);
            return requestConfigBuilder;
        });
        restClientBuilder.setHttpClientConfigCallback(httpClientBuilder -> {
            httpClientBuilder.setMaxConnTotal(8);
            if (StringUtils.isNotEmpty(esConfig.getPrincipal())) {
                final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
                credentialsProvider.setCredentials(AuthScope.ANY,
                                                   new UsernamePasswordCredentials(esConfig.getPrincipal(), esConfig.getPassword()));
                httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
            }
            return httpClientBuilder;
        });
        return new RestHighLevelClient(restClientBuilder);
    }

    public static void initRestClientBuilder() {
        // 从池中取一个对象
        String[] hosts = esConfig.getServerHost().split(",");
        int length = hosts.length;
        HttpHost[] httpHosts = new HttpHost[length];
        for (int i = 0; i < length; i++) {
            String[] ipAndPort = hosts[i].split(":");
            httpHosts[i] = new HttpHost(ipAndPort[0], Integer.valueOf(ipAndPort[1]), esConfig.getSchema());
        }
        try {
            restClientBuilder = getRestClientBuilder(httpHosts);
        } catch (Exception e) {
            LOGGER.error("initRestClientBuilder error", e);
        }
    }

    /**
     * 归还对象.
     *
     * @param client client
     */
    public static void returnClient(RestHighLevelClient client) {
        if (null != client) {
            // 使用完毕之后，归还对象
            try {
                client.close();
            } catch (IOException e) {
                LOGGER.error("RestHighLevelClient close error", e);
            }
        }
    }

    /**
     * Get one rest client builder instance
     */
    private static RestClientBuilder getRestClientBuilder(HttpHost[] hostArray) throws Exception {
        RestClientBuilder builder = RestClient.builder(hostArray);
        Header[] defaultHeaders = new Header[] {new BasicHeader("Accept", "application/json"),
                new BasicHeader("Content-type", "application/json")};

        builder = builder.setRequestConfigCallback(requestConfigBuilder -> requestConfigBuilder.setConnectTimeout(esConfig.getConnectTimeout())
                .setSocketTimeout(esConfig.getSocketTimeout())
                .setConnectionRequestTimeout(esConfig.getConnectionRequestTimeout()));

        builder.setDefaultHeaders(defaultHeaders);

        return builder;
    }



    /**
     * .
     *
     * @return esConfig
     */
    public static EsConfigInterface getEsConfig() {
        return esConfig;
    }

    /**
     * .
     *
     * @param esConfig to set
     */
    public static void setEsConfig(final EsConfigInterface esConfig) {
        ElasticSearchPoolUtil.esConfig = esConfig;
    }
}
